﻿using System;
using System.Linq.Expressions;
using System.Reflection;
using Fabrication.Exceptions;

namespace Fabrication.Extensions
{
    internal static class ExpressionExtensions
    {
        public static string GetPropertyName<T, TParam>(this Expression<Func<T, TParam>> member)
        {
            var memberExpression = ExtractMemberExpression(member);

            return memberExpression.Member.Name;
        }

        public static string GetPropertyNameIfNotReadOnly<T, TParam>(this Expression<Func<T, TParam>> member)
        {
            var memberExpression = ExtractMemberExpression(member);

            var property = memberExpression.Member.DeclaringType.GetProperty(memberExpression.Member.Name);
            if (!property.CanWrite)
                throw new PropertySelectorException(string.Format("Property selector cannot be created for '{0}' because it is read only.", memberExpression.Member.Name));

            return memberExpression.Member.Name;
        }

        private static MemberExpression ExtractMemberExpression<T, TParam>(Expression<Func<T, TParam>> member)
        {
            if (member == null)
                throw new PropertySelectorException("Property selector cannot be null.");

            var memberExpression = member.Body as MemberExpression;
            if (memberExpression == null || memberExpression.Member.MemberType != MemberTypes.Property)
                throw new PropertySelectorException("Property selector must target a valid property.");

            return memberExpression;
        }
    }
}